﻿using DevExpress.Data.Helpers;
using DevExpress.XtraBars;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Controls;
using DevExpress.XtraGrid.Views.Base;
using DevExpress.XtraGrid.Views.Grid;
using Rimifier.Properties;
using Rimifier.Support;
using Rimifier.Support.ResourceManager;
using Rimifier.Support.ZoneManager;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using System.Xml.Linq;

namespace Rimifier
{
  public partial class MainTabbedScreen : BaseForm
  {

    private List<Int32> _allId;

    public MainTabbedScreen()
    {
      InitializeComponent();

      // This line of code is generated by Data Source Configuration Wizard
      GridZones.DataSource = new List<ZoneList>();
    }

    private void Output(String text)
    {
      TextOutput.Text = TextOutput.Text + Environment.NewLine + text;
    }

    private void LoadAllId(){
      Output("Loading all Ids");
      var allId = UtilityFunctions.GetMainSaveFileAsElement().Descendants().Where(x => x.Name == "id").ToList();

      if (allId.Any())
      {
        foreach (var oneId in allId)
        {
          _allId.Add(Int32.Parse(new String(oneId.Value.Where(Char.IsDigit).ToArray())));
        }
      }

      _allId.Sort();
    }

    private void LoadResources()
    {
			var saveCursor = Cursor.Current;

			try
			{

				Cursor.Current = Cursors.WaitCursor;
				GridZones.DataSource = null;

        var allZones = UtilityFunctions.GetMainSaveFileAsList("allZones").Descendants().Where(x => x.HasAttributes && x.Attributes().Any(y => y.Value == "Zone_Stockpile"));

				if (allZones.Any())
				{
					// var actualAllZones = allZones.Nodes().ToList();
					var retrievedZones = new ZoneList();

					// Get resource item on slab here          
          var allTheResources = UtilityFunctions.GetMainSaveFileAsList("things").Descendants().Where(x => x.HasAttributes && x.Attributes().Any(y => y.Value == "ThingWithComponents")).Where(count => count.Ancestors().Count() == 2).ToList();

					var matchedResources = new List<Resource>();

					foreach (var oneTheResource in allTheResources)
					{
						var elementNodes = oneTheResource.Nodes().Select(x => (XElement)x).ToList();

						try
						{
							matchedResources.Add(new Resource
							{
								Def = elementNodes.Single(where => @where.Name == "def").Value,
								Id = elementNodes.Single(where => @where.Name == "id").Value,
								ResourceType = (new ResourceTypes()).Resources().Single(w => w.Name == elementNodes.Single(where => @where.Name == "def").Value),
								Pos = elementNodes.Single(where => @where.Name == "pos").Value,
								StackCount = Int32.Parse(elementNodes.Single(where => @where.Name == "stackCount").Value)
							});
						}
						catch (Exception)
						{
							Console.WriteLine();
							Console.WriteLine("Resource loop error: {0}", oneTheResource.Value);
						}
					}

          foreach (var oneZone in allZones)
					{
						var tempExpandedZone = ((XElement)(oneZone)).Nodes().Select(x => (XElement)x).ToList();

						var tempZone = new Zone
						{
							Name = tempExpandedZone.Single(where => @where.Name == "zoneName").Value,
							OldName = tempExpandedZone.Single(where => @where.Name == "zoneName").Value,
							Color = tempExpandedZone.Single(where => @where.Name == "zoneColor").Value,
							Priority = tempExpandedZone.Single(where => where.Name == "settings").Nodes().Select(x => (XElement)x).ToList().Single(where => where.Name == "priority").Value,
						};

						tempZone.ZoneSlabs.AddRange(tempExpandedZone.Single(where => where.Name == "squares").Nodes().Select(x => (XElement)x).ToList().Select(x => x.Value).Select(y => new ZoneSquare(tempZone, y)));

						foreach (var zoneSquare in tempZone.ZoneSlabs)
						{
							if (matchedResources.Any(w => w.Pos == zoneSquare.Positon))
							{
								zoneSquare.SittingResource = matchedResources.First(w => w.Pos == zoneSquare.Positon);
							}
						}

						retrievedZones.Add(tempZone);
					}

					GridZones.DataSource = retrievedZones;

					#region Calculate on-hand
					var iSilver = 0;
					foreach (var oneZone in retrievedZones.Select(x => x.ZoneSlabs.Where(y => y.SittingResource != null && y.SittingResource.Def == "Silver")))
					{
						iSilver += oneZone.Sum(a => a.StackCount);
					}
					TextCurrentResources_Silver.Text = iSilver.ToString(CultureInfo.InvariantCulture);

					var iPotatoes = 0;
					foreach (var oneZone in retrievedZones.Select(x => x.ZoneSlabs.Where(y => y.SittingResource != null && y.SittingResource.Def == "Potatoes")))
					{
						iPotatoes += oneZone.Sum(a => a.StackCount);
					}
					TextCurrentResources_Potatoes.Text = iPotatoes.ToString(CultureInfo.InvariantCulture);

					var iMetal = 0;
					foreach (var oneZone in retrievedZones.Select(x => x.ZoneSlabs.Where(y => y.SittingResource != null && y.SittingResource.Def == "Metal")))
					{
						iMetal += oneZone.Sum(a => a.StackCount);
					}
					TextCurrentResources_Metal.Text = iMetal.ToString(CultureInfo.InvariantCulture);
					#endregion
					
				}
				else
				{
					// Load failed
					BarManagerMain_StatusBar_StaticItemReport.Caption = Resources.LoadResourcesFailed;
				}

			}
			finally
			{
				Cursor.Current = saveCursor;
			}     
    }

    #region Form Events

    private void MainTabbedScreen_Load(object sender, EventArgs e)
    {
      Output("Application started");
      _allId = new List<Int32>();

      // Set the correct tab page
      Output("Select first tab page");
      XtraTabMain.SelectedTabPage = XtraTabMainPage01General;

      // Set the stockpile priorities
      Output("Set the stockpile priorities");
      GridZones_ViewZones_ColumnPriority_RepositoryCombo.Items.Clear();
      GridZones_ViewZones_ColumnPriority_RepositoryCombo.Items.AddRange(new StockpilePriority().Priorities());

      // Set the stockpile resources
      Output("Set the stockpile resources");
      GridZones_ViewZonesSquares_ColumnSittingResource_RepositoryItemCombo.Items.Clear();
      foreach (var oneResource in new ResourceTypes().Resources())
      {
        GridZones_ViewZonesSquares_ColumnSittingResource_RepositoryItemCombo.Items.Add(Resource.CreateDefaultResource(oneResource));
      }
    }

    private void BarManagerMain_StatusBar_ButtonPaypal_ItemClick(object sender, ItemClickEventArgs e)
    {
      var url = "";
      const string business = "hassan.gulzar@gmail.com";
      var description = String.Format("Donate{0}something{1}{0}Not{0}that{0}it{0}is{0}required{0}but{0}if{0}you{0}don{2}t{0}mind{3}{0}then{0}I{0}definitely{0}don{2}t{0}either{4}", "%20", "%2E", "%B4", "%2C", "%21");
      const string country = "US";
      const string currency = "USD";
      url += String.Format("https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business={0}&lc={1}&item_name={2}&currency_code={3}&bn=PP%2dDonationsBF", business, country, description, currency);
      Process.Start(url);
    }

    private void BarManagerMain_StatusBar_ButtonAbout_ItemClick(object sender, ItemClickEventArgs e)
    {
      new AboutApp().ShowDialog(this);
    }

    #endregion

    #region Save File

    private void ButtonLoad_Click(object sender, EventArgs e)
    {
      BarManagerMain_StatusBar_StaticItemReport.Caption = Resources.Basic_String_Status;

      OpenSaveFileDialog.InitialDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), Resources.RimWorldSaveFileLocation);

      if (OpenSaveFileDialog.ShowDialog(this) == DialogResult.OK)
      {

        #region Opening file

        var directoryInfo = new FileInfo(OpenSaveFileDialog.FileName).Directory;
        if (directoryInfo != null)
        {
          Settings.Default.SelectedSaveFilePath = OpenSaveFileDialog.FileName;
          Settings.Default.BackupSaveFilePath = directoryInfo.FullName + Resources.RimWorldSaveFileBackupLocation;
        }
        else
        {
          XtraMessageBox.Show(Resources.CouldnTLoadAnything, UtilityFunctions.AssemblyTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
          return;
        }

        #endregion

        var xmlList = UtilityFunctions.GetMainSaveFileAsList();

        #region Save File

        TextSavePath.Text = OpenSaveFileDialog.FileName;
        var selectSingleNode = xmlList.SingleOrDefault(where => where.Name == "gameVersion");
        if (selectSingleNode != null)
        {
          TextGameVersion.Text = selectSingleNode.Value;
        }

        #endregion

        #region Map Info

        selectSingleNode = xmlList.SingleOrDefault(where => where.Name == "colonyName");
        if (selectSingleNode != null)
        {
          TextColonyName.Text = selectSingleNode.Value;
        }

        selectSingleNode = xmlList.SingleOrDefault(where => where.Name == "mapInfo");
        if (selectSingleNode != null)
        {
          var tempList = selectSingleNode.Nodes().Select(x => (XElement)x).ToList();
          TextMapName.Text = tempList.Single(where => where.Name == "name").Value;
          TextMapSize.Text = tempList.Single(where => where.Name == "size").Value;
          TextWorldCoords.Text = tempList.Single(where => where.Name == "worldCoords").Value;
          TextWorldName.Text = tempList.Single(where => where.Name == "worldFileName").Value;
        }

        #endregion

        LoadAllId();
        LoadResources();
        // LoadColonists();

        BarManagerMain_StatusBar_StaticItemReport.Caption = Resources.Basic_String_Status_Loaded_Success;
      }
      else
      {
        BarManagerMain_StatusBar_StaticItemReport.Caption = Resources.Basic_String_Status_Loaded_Failed;
      }
    }

    #endregion

    #region Zone/Resources

		private void ButtonSaveZone_Click(object sender, EventArgs e)
		{
			var saveCursor = Cursor.Current;

			try
			{
				Cursor.Current = Cursors.WaitCursor;

				var modifiedZones = GridZones.DataSource as ZoneList;

				if (modifiedZones == null)
				{
					Cursor.Current = saveCursor;
					XtraMessageBox.Show("There are no zones to play with.", UtilityFunctions.AssemblyTitle, MessageBoxButtons.OK, MessageBoxIcon.Warning);
					return;
				}

				if (modifiedZones.Any() && modifiedZones.GroupBy(x => x.OldName).Any(g => g.Count() > 1))
				{
					// Zone name duplicate!
					Cursor.Current = saveCursor;				
					XtraMessageBox.Show("There are zones with same name. Please name every zone uniquely.", UtilityFunctions.AssemblyTitle, MessageBoxButtons.OK, MessageBoxIcon.Warning);
					return;
				}

				var currentSaveFile = UtilityFunctions.GetMainSaveFileAsXml();

				UtilityFunctions.BackupSaveFile("ZoneManager");

				foreach (var oneZone in modifiedZones)
				{
					var targetZone = currentSaveFile.Element("Map").Element("ZoneManager").Element("AllZones").Elements("Zone").Where(fixer => fixer.Element("zoneName").Value == oneZone.OldName).Single();

					// Name
					targetZone.Element("zoneName").Value = oneZone.Name;

					// Color
					targetZone.Element("zoneColor").Value = oneZone.Color;

					// Priority
					targetZone.Element("settings").Element("priority").Value = oneZone.Priority;

					foreach (var oneSquare in oneZone.ZoneSlabs)
					{
						var localSittingResource = oneSquare.SittingResource;
						if (oneSquare.SittingResource != null)
						{
							// Check if same resource (pre-existing)
							var targetNewResourceCheck = targetZone.Element("squares").Nodes().Where(fixer => (fixer as XElement).Value == localSittingResource.Pos).SingleOrDefault();
							if (targetNewResourceCheck != null)
							{
								// This one is pre-existing
								// Retrieve the resource by Position
								var seekResourcePos = currentSaveFile.Descendants().Where(x => x.Name == "Pos" && x.Value == (targetNewResourceCheck as XElement).Value);
								if (seekResourcePos != null)
								{
									var parentRes = seekResourcePos.Ancestors().First();
									parentRes.SetElementValue("Def", localSittingResource.Def);
									parentRes.SetElementValue("ID", localSittingResource.Def + new String(localSittingResource.Id.Where(Char.IsDigit).ToArray()));
									parentRes.SetElementValue("StackCount", localSittingResource.StackCount);
									parentRes.SetElementValue("Forbidden", "False");
								}
							}
							else
							{
								// We have a resource to add
								var newResource = new XElement("Thing", new XAttribute("Class", "ThingResource"));
								newResource.Add(new XElement("Def", localSittingResource.Def));
								newResource.Add(new XElement("ID", localSittingResource.Def + UtilityFunctions.ControlledNewId(_allId, 100000, 999999)));
								newResource.Add(new XElement("Pos", oneSquare.Positon));
								newResource.Add(new XElement("StackCount", localSittingResource.StackCount));
								newResource.Add(new XElement("Forbidden", "False"));
								currentSaveFile.Element("Map").Element("Things").Add(newResource);
							}
						}
					}
				}

				currentSaveFile.Save(Settings.Default.SelectedSaveFilePath);

				LoadResources();

				BarManagerMain_StatusBar_StaticItemReport.Caption = Resources.Basic_String_Status_ZonesModifiedSuccess;
			}
			finally
			{
				Cursor.Current = saveCursor;
			}

		}

    private void GridZones_ViewZones_RowStyle(object sender, RowStyleEventArgs e)
    {
      var view = sender as GridView;

      if (view != null && e.RowHandle > 0)
      {
        var xColor = view.GetRowCellValue(e.RowHandle, view.Columns["ZoneColor"]);

        if (xColor != null)
        {
          e.Appearance.BackColor = (Color)xColor;
          e.Appearance.BackColor2 = Color.White;
        }        
      }
    }

    private void GridZones_ViewZones_CustomUnboundColumnData(object sender, CustomColumnDataEventArgs e)
    {
      try
      {
        var view = sender as GridView;

        if (view != null && view.DataSource != null)
        {
          var dv = (((ListIEnumerable)view.DataSource).Source) as ZoneList;

          if (dv != null)
          {
            if (e.IsGetData)
            {
              e.Value = (new ColorRGBA(dv[e.ListSourceRowIndex].Color)).GetColor();
            }
            else
            {
              dv[e.ListSourceRowIndex].Color = ColorRGBA.GetGameColor((Color)e.Value);
            }
          }
        }
      }
      finally
      {

      }
    }

    private void GridZones_ViewZonesSquares_ColSittingResource_RepositoryItemCombo_ButtonClick(object sender, ButtonPressedEventArgs e)
    {
      if (e.Button.Kind == ButtonPredefines.Delete)
      {
        var comboBoxEdit = sender as ComboBoxEdit;
        if (comboBoxEdit != null)
        {
          comboBoxEdit.EditValue = null;
        }
      }
    }

    #endregion

  }

}